package cn.maihe.elg.operation.supports.electronicseal.kt;

import cn.maihe.elg.operation.model.bo.GuaranteeTemplatePdfParams;
import cn.maihe.elg.operation.model.bo.ReceiveTemplatePdfParams;
import cn.maihe.elg.operation.model.enums.GuaranteeTemplateType;
import cn.maihe.elg.operation.supports.system.ElgResourceService;
import cn.maihe.elg.operation.utils.ValidateUtil;
import com.google.common.collect.Lists;
import com.kinsec.KTConvert;
import com.kinsec.KTSignature;
import com.kinsec.SignatureInfo;
import com.kinsec.dom.Attachment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;

/**
 * @Description 凯特电子签章&转换服务
 * @Author WJH
 * @Date 2021/04/26
 */
@Service
@Slf4j
public class KtOFDService {

    private final KtConfig ktConfig;
    private final KTSignature ktSignature;
    private final KTConvert ktConvert;
    private ElgResourceService elgResourceService;


    private final KtConfig.SealInfo ztSealInfo;

    public KtOFDService(KtConfig ktConfig, ElgResourceService elgResourceService) {
        this.ktConfig = ktConfig;
        Assert.hasText(ktConfig.getServerUrl(), () -> "凯特签章服务地址cn.maihe.elg.kt.serverUrl未配置");
        ktSignature = new KTSignature(ktConfig.getServerUrl());
        ktConvert = new KTConvert(ktConfig.getServerUrl());

        this.elgResourceService = elgResourceService;
        this.ztSealInfo = ktConfig.getSealInfoByKey(KtConfig.SealInstitution.deXing);
    }


    /**
     * srcFile [String]	待签章文件路径
     * Page [int]	签章页码
     * 0：第一页
     * -1：所有页面
     * -2：最后一页
     * sealID [String]	印章ID
     * certIndexPasswd [String]	签章密码
     * x [float]	印章x轴坐标
     * y [float]	印章y轴坐标
     * Out [OutputStream]	输出签章后的文件路径
     */
    public boolean singleSeal(String srcOfdFile, SignatureInfo signatureInfo, String saveOfdFile) {
        boolean singleSealTf = false;
//        try {
//            Assert.isTrue(srcOfdFile.toLowerCase().endsWith(".ofd"), "待签章文件必须为ofd类型");
//            Assert.isTrue(Files.exists(Paths.get(srcOfdFile)), () -> "源ofd签章文件不存在");
//            Assert.notNull(signatureInfo, () -> "印章属性对象不能为空");
//            Assert.hasText(saveOfdFile, () -> "保存签章ofd文件路径不能为空");
//            Assert.isTrue(saveOfdFile.toLowerCase().endsWith(".ofd"), "保存签章文件必须为ofd类型");

//            singleSealTf = ktSignature.kt_ofdStamp(srcOfdFile, signatureInfo.getPage(), signatureInfo.getSealID(), signatureInfo.getPassword(),
//                    signatureInfo.getX(), signatureInfo.getY(), new FileOutputStream(saveOfdFile));
//        } catch (IOException e) {
//            throw new RuntimeException("凯特电子签章异常:" + e.getMessage(), e);
//        }
        return singleSealTf;
    }

    /**
     * 联合电子签章
     */
    public boolean unionSeal(Path sourceOfdPath, ArrayList<SignatureInfo> signatureInfos, Path sealedOfdPath) {
        boolean unionSealTf = false;
//        try {
//            Assert.isTrue(Files.exists(sourceOfdPath), () -> "源ofd签章文件不存在");
//            Assert.notEmpty(signatureInfos, () -> "印章属性对象不能为空");
//            Assert.notNull(sealedOfdPath, () -> "保存签章ofd文件路径不能为空");
//
//            unionSealTf = ktSignature.kt_ofdStamps(sourceOfdPath.toString(), signatureInfos,
//                    Files.newOutputStream(sealedOfdPath));
//        } catch (IOException e) {
//            throw new RuntimeException("凯特电子签章异常:" + e.getMessage(), e);
//        }
        return unionSealTf;
    }

    /**
     * 将单个PDF文件转换为OFD文件(支持html,pdf,doc,xls,不支持jpg,png)
     */
    public boolean convertOfficeToOFD(Path srcOfficeFile, Path saveOfdFile) {
        return convertOfficeToOFD(srcOfficeFile.toString(), saveOfdFile.toString());
    }

    public boolean convertOfficeToOFD(String srcOfficeFile, String saveOfdFile) {
        Assert.isTrue(srcOfficeFile.toLowerCase().endsWith(".pdf")
                || srcOfficeFile.toLowerCase().endsWith(".doc") || srcOfficeFile.toLowerCase().endsWith(".docx"), "源转换文件必须为pdf|docx|doc类型");
        Assert.isTrue(saveOfdFile.toLowerCase().endsWith(".ofd"), "转换后文件必须为ofd类型");

        try {
            ktConvert.kt_officeToOFD(srcOfficeFile, new FileOutputStream(saveOfdFile));
        } catch (Exception e) {
            throw new RuntimeException("office文件转ofd文件异常:" + e.getMessage(), e);
        }
        return true;
    }

    /**
     * 转换ofd并带附件
     *
     * @param srcOfficeFile 带附件的转换，目前源文件只支持pdf ofd格式
     * @param saveOfdFile
     * @param title          附件名称
     * @param fileType       附件类型
     * @param attachmentFile 附件源文件路径
     */
    public boolean convertOfdWithAttachment(String srcOfficeFile, String saveOfdFile, String title, String fileType, String attachmentFile) {
        Assert.isTrue(srcOfficeFile.toLowerCase().endsWith(".pdf")
                || srcOfficeFile.toLowerCase().endsWith(".ofd"), "源转换文件必须为pdf|ofd类型");
        Assert.isTrue(saveOfdFile.toLowerCase().endsWith(".ofd"), "转换后文件必须为ofd类型");

        Path srcPath = Paths.get(srcOfficeFile);
        Assert.isTrue(Files.exists(Paths.get(srcOfficeFile)), () -> "源转换文件不存在");
        try {
            ktConvert.kt_addAttachment(srcPath.toFile(), new FileOutputStream(saveOfdFile), title, fileType, new FileInputStream(attachmentFile));
        } catch (Exception e) {
            throw new RuntimeException("转换ofd文件异常:" + e.getMessage(), e);
        }
        return true;
    }

    /**
     * 转换ofd并带多附件
     *
     * @param srcOfficeFile 带附件的转换，目前源文件只支持pdf ofd格式
     * @param saveOfdFile
     * @param attachments
     * @return
     */
    public boolean convertOfdWithAttachments(String srcOfficeFile, String saveOfdFile, ArrayList<Attachment> attachments) {
        Assert.isTrue(srcOfficeFile.toLowerCase().endsWith(".pdf")
                || srcOfficeFile.toLowerCase().endsWith(".ofd"), "源转换文件必须为pdf|ofd类型");
        Assert.isTrue(saveOfdFile.toLowerCase().endsWith(".ofd"), "转换后文件必须为ofd类型");

        Path srcPath = Paths.get(srcOfficeFile);
        Assert.isTrue(Files.exists(Paths.get(srcOfficeFile)), () -> "源转换文件不存在");
        try {
            ktConvert.kt_addAttachment(srcPath.toFile(), new FileOutputStream(saveOfdFile), attachments);
        } catch (Exception e) {
            throw new RuntimeException("转换ofd文件异常:" + e.getMessage(), e);
        }
        return true;
    }


    /**
     * 电子保函签章
     * 返回 电签后的ofd文件
     */
    public Path guaranteeOfdWithAttachesSeal(String acceptOrderNo, GuaranteeTemplatePdfParams params, ArrayList<Attachment> attachments) {
        Assert.hasText(acceptOrderNo, "受理订单号不能为空");
        ValidateUtil.validate(params);
        GuaranteeTemplateType templateType = params.getGuaranteeTemplateType();
        Integer signPageNum = templateType.getSignPageNum();
        Float signOrgXpx = templateType.getSignOrgXpx();
        Float signOrgYpx = templateType.getSignOrgYpx();
        Float signLegalXpx = templateType.getSignLegalXpx();
        Float signLegalYpx = templateType.getSignLegalYpx();


        //电子保函ofd联合签章 ::page x y 值是根据现有模板内置的
        SignatureInfo companySealInfo = new SignatureInfo(signPageNum, ztSealInfo.getSealId(), ztSealInfo.getCertIndexPassWd(), signOrgXpx, signOrgYpx);
        SignatureInfo legalSealInfo = new SignatureInfo(signPageNum, ztSealInfo.getLegalSealId(), ztSealInfo.getLegalCertIndexPassWd(), signLegalXpx, signLegalYpx);
        //签章后的ofd文件
        Path targetSealOfdPath ;
        //docx转ofd文件路径：未签章
        Path unSealTargetOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "unSeal担保保函", "ofd");
        boolean tf ;
        if(attachments==null){
            //担保保函模板填充后docx文件
            Path sourceDocxPath = elgResourceService.buildGuaranteeFileByTemplate(acceptOrderNo, params);
            this.convertOfficeToOFD(sourceDocxPath, unSealTargetOfdPath);
            targetSealOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "担保保函", "ofd");
            tf = this.unionSeal(unSealTargetOfdPath, Lists.newArrayList(companySealInfo, legalSealInfo), targetSealOfdPath);
            if (tf) {
                try {
                    Files.deleteIfExists(sourceDocxPath);
                } catch (IOException e) {
                    log.error("{}:银行保函.docx异常:{}", acceptOrderNo, e.getMessage(), e);
                }
            }
        }else {
            //添加附件的转换，源文件必须为pdf或ofd
            Path unSealTargetOfdPathWithAttach = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "unSeal担保保函附件", "ofd");
            this.convertOfdWithAttachments(unSealTargetOfdPath.toString(), unSealTargetOfdPathWithAttach.normalize().toString(), attachments);
            targetSealOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, params.getGuaranteeNo(), "ofd");
            tf = this.unionSeal(unSealTargetOfdPathWithAttach, Lists.newArrayList(companySealInfo, legalSealInfo), targetSealOfdPath);
            if (tf) {
                try {
                    Files.deleteIfExists(unSealTargetOfdPath);
                    Files.deleteIfExists(unSealTargetOfdPathWithAttach);
                } catch (IOException e) {
                    log.error("{}:删除unSeal银行保函.ofd及unSeal银行保函附件.ofd异常:{}", acceptOrderNo, e.getMessage(), e);
                }
            }
        }

        if (tf) {
            return targetSealOfdPath;
        } else {
            throw new RuntimeException("担保保函签章失败");
        }
    }

    /**
     * 到账证明签章
     * 返回 电签后的ofd文件
     */
    public Path receiveOfdSeal(String acceptOrderNo, ReceiveTemplatePdfParams params) {
        Assert.hasText(acceptOrderNo, "受理订单号不能为空");
        ValidateUtil.validate(params);

        //模板填充docx
        Path targetDocPath = elgResourceService.buildReceiveFileByTemplate(acceptOrderNo, params);
        //docx转ofd
        Path targetOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "unSeal到账证明", "ofd");
        this.convertOfficeToOFD(targetDocPath, targetOfdPath);
        //电子保函ofd联合签章 ::page x y 值是根据现有模板内置的
        SignatureInfo companySealInfo = new SignatureInfo(0, ztSealInfo.getSealId(), ztSealInfo.getCertIndexPassWd(), 130, 180);
        //签章后的ofd文件
        Path targetSealOfdPath = elgResourceService.buildSaveAbsolutePath("ofd", acceptOrderNo, "到账证明", "ofd");

        boolean tf = this.unionSeal(targetOfdPath, Lists.newArrayList(companySealInfo), targetSealOfdPath);
        if (tf) {
            return targetSealOfdPath;
        } else {
            throw new RuntimeException("到账证明签章失败");
        }
    }


}
